#include "tiffiop.h"
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

static tsize_t
_tiffReadProc( thandle_t fd, tdata_t buf, tsize_t size ) {
  return ( ( tsize_t ) read( ( int ) fd, buf, ( size_t ) size ) );
}

static tsize_t
_tiffWriteProc( thandle_t fd, tdata_t buf, tsize_t size ) {
  return ( ( tsize_t ) write( ( int ) fd, buf, ( size_t ) size ) );
}

static toff_t
_tiffSeekProc( thandle_t fd, toff_t off, int whence ) {
  #if USE_64BIT_API == 1
  return ( ( toff_t ) lseek64( ( int ) fd, ( off64_t ) off, whence ) );
  #else
  return ( ( toff_t ) lseek( ( int ) fd, ( off_t ) off, whence ) );
  #endif
}

static int
_tiffCloseProc( thandle_t fd ) {
  return ( close( ( int ) fd ) );
}

#include <sys/stat.h>

static toff_t
_tiffSizeProc( thandle_t fd ) {
  #ifdef _AM29K
  long fsize;
  return ( ( fsize = lseek( ( int ) fd, 0, SEEK_END ) ) < 0 ? 0 : fsize );
  #else
  #if USE_64BIT_API == 1
  struct stat64 sb;
  return ( toff_t )( fstat64( ( int ) fd, &sb ) < 0 ? 0 : sb.st_size );
  #else
  struct stat sb;
  return ( toff_t )( fstat( ( int ) fd, &sb ) < 0 ? 0 : sb.st_size );
  #endif
  #endif
}

#ifdef HAVE_MMAP
#include <sys/mman.h>

static int
_tiffMapProc( thandle_t fd, tdata_t* pbase, toff_t* psize ) {
  toff_t size = _tiffSizeProc( fd );
  if( size != ( toff_t ) - 1 ) {
    *pbase = ( tdata_t )
             mmap( 0, size, PROT_READ, MAP_SHARED, ( int ) fd, 0 );
    if( *pbase != ( tdata_t ) - 1 ) {
      *psize = size;
      return ( 1 );
    }
  }
  return ( 0 );
}

static void
_tiffUnmapProc( thandle_t fd, tdata_t base, toff_t size ) {
  ( void ) fd;
  ( void ) munmap( base, ( off_t ) size );
}
#else /* !HAVE_MMAP */
static int
_tiffMapProc( thandle_t fd, tdata_t* pbase, toff_t* psize ) {
  ( void ) fd;
  ( void ) pbase;
  ( void ) psize;
  return ( 0 );
}

static void
_tiffUnmapProc( thandle_t fd, tdata_t base, toff_t size ) {
  ( void ) fd;
  ( void ) base;
  ( void ) size;
}
#endif /* !HAVE_MMAP */

/*
   Open a TIFF file descriptor for read/writing.
*/
TIFF*
TIFFFdOpen( int fd, const char* name, const char* mode ) {
  TIFF* tif;
  tif = TIFFClientOpen( name, mode,
                        ( thandle_t ) fd,
                        _tiffReadProc, _tiffWriteProc,
                        _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
                        _tiffMapProc, _tiffUnmapProc );
  if( tif ) {
    tif->tif_fd = fd;
  }
  return ( tif );
}

TIFF*
TIFFOpen( const char* name, const char* mode ) {
  static const char module[] = "TIFFOpen";
  int m, fd;
  m = _TIFFgetMode( mode, module );
  if( m == -1 ) {
    return ( ( TIFF* )0 );
  }
  /* for cygwin */
  #ifdef O_BINARY
  m |= O_BINARY;
  #endif
  #ifdef _AM29K
  fd = open( name, m );
  #else
  #if USE_64BIT_API == 1
  fd = open( name, m | O_LARGEFILE, 0666 );
  #else
  fd = open( name, m, 0666 );
  #endif
  #endif
  if( fd < 0 ) {
    TIFFError( module, "%s: Cannot open", name );
    return ( ( TIFF * )0 );
  }
  return ( TIFFFdOpen( fd, name, mode ) );
}

void*
_TIFFmalloc( tsize_t s ) {
  return ( malloc( ( size_t ) s ) );
}

void
_TIFFfree( tdata_t p ) {
  free( p );
}

void*
_TIFFrealloc( tdata_t p, tsize_t s ) {
  return ( realloc( p, ( size_t ) s ) );
}

void
_TIFFmemset( tdata_t p, int v, tsize_t c ) {
  memset( p, v, ( size_t ) c );
}

void
_TIFFmemcpy( tdata_t d, const tdata_t s, tsize_t c ) {
  memcpy( d, s, ( size_t ) c );
}

int
_TIFFmemcmp( const tdata_t p1, const tdata_t p2, tsize_t c ) {
  return ( memcmp( p1, p2, ( size_t ) c ) );
}

static void
unixWarningHandler( const char* module, const char* fmt, va_list ap ) {
  if( module != NULL ) {
    fprintf( stderr, "%s: ", module );
  }
  fprintf( stderr, "Warning, " );
  vfprintf( stderr, fmt, ap );
  fprintf( stderr, ".\n" );
}
TIFFErrorHandler _TIFFwarningHandler = unixWarningHandler;

static void
unixErrorHandler( const char* module, const char* fmt, va_list ap ) {
  if( module != NULL ) {
    fprintf( stderr, "%s: ", module );
  }
  vfprintf( stderr, fmt, ap );
  fprintf( stderr, ".\n" );
}
TIFFErrorHandler _TIFFerrorHandler = unixErrorHandler;
